package com.den4.jynform;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import org.quartz.CronTrigger;
import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParser;

import com.den4.jynform.alerts.EmailLogger;
import com.den4.jynform.alerts.GoogleTalkLogger;

/**
 * Class that handles the reading/writing of job configurations.  This object
 * is a singleton that reads the job configurations when it first gets created.
 * Whenever any job is deleted, added, or updated this file is serialized. 
 * @author abargnesi
 */
public class Configurer {
    private static Configurer instance = null;
    private static InputStream fileInput;
    private List<JobBean> jobs = new ArrayList<JobBean>();
    private JobBean currentJob;
    private int alertType = -1;
    private final static String JOB = "job";
    private final static String PARAM = "param";
    private final static String CRON = "cron";
    private final static String ONFAIL = "onfail";
    private final static String ONSUCCESS = "onsuccess";
    private final static String EMAIL = "email";
    private final static String GTALK = "gtalk";
    
    public static Configurer getInstance(InputStream is) {
        if (instance == null) {
            fileInput = is;
            instance = new Configurer();
        }
        return instance;
    }

    public static Configurer getInstance() {
        if (instance == null) {
            instance = new Configurer();
        }
        return instance;
    }
    
    public static void resetConfiguration() {
        instance = null;
    }

    private Configurer() {
        try {
            read();
        } catch (Exception e) {}
    }
    
    public List<JobBean> getJobs() {
        return jobs;
    }
    
    /**
     * Parses jobdef.xml into schedulable <code>jobs</code> with an associated trigger.
     */
    public void read() throws Exception {
        XmlPullParser parser = new MXParser();
        if(fileInput != null) {
            parser.setInput(new InputStreamReader(fileInput));
        } else {
            //Default.
            parser.setInput(new InputStreamReader(Configurer.class
                .getResourceAsStream("/com/den4/tasks/jobdef.xml")));
        }
        
        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_DOCUMENT) {
            } else if (eventType == XmlPullParser.END_DOCUMENT) {
            } else if (eventType == XmlPullParser.START_TAG) {
                doElementStart(parser);
            } else if (eventType == XmlPullParser.END_TAG) {
                doElementEnd(parser);
            } else if (eventType == XmlPullParser.TEXT) {
            }
            eventType = parser.next();
        }
    }
    
    private void doElementStart(XmlPullParser parser) throws ParseException {
        if(JOB.equals(parser.getName())) {
            currentJob = new JobBean(Integer.parseInt(parser
                    .getAttributeValue(0)), parser.getAttributeValue(1));
        } else if(PARAM.equals(parser.getName())) {
            currentJob.getParams().put(parser.getAttributeValue(0),
                    parser.getAttributeValue(1));
        } else if(CRON.equals(parser.getName())) {
            CronTrigger cTrg = new CronTrigger();
            cTrg.setCronExpression(parser.getAttributeValue(0));
            currentJob.getTriggers().add(cTrg);
        } else if(ONFAIL.equals(parser.getName())) {
            alertType = 0;
        } else if(ONSUCCESS.equals(parser.getName())) {
            alertType = 1;
        } else if(EMAIL.equals(parser.getName())) {
            EmailLogger eLogger = new EmailLogger();
            eLogger.setHost(parser.getAttributeValue(0));
            eLogger.setUser(parser.getAttributeValue(1));
            eLogger.setPass(parser.getAttributeValue(2));
            eLogger.setFromAddress(parser.getAttributeValue(3));
            eLogger.setToAddress(parser.getAttributeValue(4));
            
            switch(alertType) {
            case 0: currentJob.setOnFailLogger(eLogger); break;
            case 1: currentJob.setOnSuccessLogger(eLogger); break;
            }
            
            alertType = -1;
        } else if(GTALK.equals(parser.getName())) {
            GoogleTalkLogger gtLogger = new GoogleTalkLogger();
            gtLogger.setLoginUser(parser.getAttributeValue(0));
            gtLogger.setLoginPass(parser.getAttributeValue(1));
            gtLogger.setRecipientUser(parser.getAttributeValue(2));            
            
            switch(alertType) {
            case 0: currentJob.setOnFailLogger(gtLogger); break;
            case 1: currentJob.setOnSuccessLogger(gtLogger); break;
            }
            
            alertType = -1;
        }
    }

    private void doElementEnd(XmlPullParser parser) {
        if(JOB.equals(parser.getName())) {
            jobs.add((JobBean) currentJob.clone());
            
            //Nullify the currentJob instance.  Seeing a new "<job>" (job start tag)
            //will initialize currentJob to an instance of JobBean.  If it does not
            //then any accessing of this instance will throw an NPE.
            currentJob = null;
        }
    }
}
